<template>
  <div
    ref="codeEditBox"
    class="codeEditBox"
    :style="{
      width,
      height
    }"
    v-bind="$attrs"
  >
    <slot />
  </div>
</template>

<script lang="ts">
// https://github.com/microsoft/monaco-editor

import { defineComponent, onBeforeUnmount, onMounted, ref, watch } from "vue";
import * as monaco from "monaco-editor";
import { editorProps } from "./monacoEditorType";
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
import EditorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";

export default defineComponent({
  props: editorProps,
  emits: ["update:modelValue", "change", "editor-mounted"],
  setup(props, { emit, expose, attrs }) {
    self.MonacoEnvironment = {
      getWorker(_: string, label: string) {
        if (label === "json") {
          return new jsonWorker();
        }
        if (["css", "scss", "less"].includes(label)) {
          return new cssWorker();
        }
        if (["html", "handlebars", "razor"].includes(label)) {
          return new htmlWorker();
        }
        if (["typescript", "javascript"].includes(label)) {
          return new tsWorker();
        }
        return new EditorWorker();
      }
    };
    let editor: monaco.editor.IStandaloneCodeEditor;
    const codeEditBox = ref();

    const handleWindowResize = () => {
      // 重新计算编辑器大小
      editor?.layout();
    };

    const init = () => {
      monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
        noSemanticValidation: true,
        noSyntaxValidation: false
      });
      monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
        target: monaco.languages.typescript.ScriptTarget.ES2020,
        allowNonTsExtensions: true
      });

      editor = monaco.editor.create(codeEditBox.value, {
        value: props.modelValue,
        language: props.language,
        theme: props.theme,
        ...props.options
      });

      // 更新编辑器大小
      window.addEventListener("resize", handleWindowResize);

      // monaco.editor.onDidChangeMarkers(([uri]) => {
      //   const markers = monaco.editor.getModelMarkers({ resource: uri });
      //   console.log("markers: ", markers);
      //   const errMsg = markers.map(({ message, startLineNumber, startColumn, endLineNumber, endColumn }) => {
      //     return `${message} [${startLineNumber}:${startColumn}-${endLineNumber}:${endColumn}]`;
      //   });
      //   console.log("自定义监听标记:", errMsg);
      // });

      // editor.addAction({
      // 	id: "hello", // 菜单项 id
      // 	label: "hello", // 菜单项名称
      // 	keybindings: [
      // 		// 绑定快捷键
      // 		monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyC
      // 	],
      // 	contextMenuGroupId: "9_cutcopypaste", // 所属菜单的分组(会被添加到右键菜单)
      // 	run: (ed: monaco.editor.ICodeEditor) => {
      // 		// 点击后或运行快捷键时执行
      // 		alert("ctrl + shift + c");
      // 	}
      // });

      // 注册光标移动快捷键
      editor.addAction({
        id: "myUpArrow",
        label: "myUpArrow",
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyI],
        run: () => {
          const pos = editor.getPosition();
          if (pos?.lineNumber) {
            const nPos: monaco.IPosition = {
              lineNumber: pos.lineNumber - 1,
              column: pos.column
            };
            editor.setPosition(nPos);
          }
        }
      });

      editor.addAction({
        id: "myDownArrow",
        label: "myDownArrow",
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyK],
        run: () => {
          const pos = editor.getPosition();
          if (pos?.lineNumber) {
            const nPos: monaco.IPosition = {
              lineNumber: pos.lineNumber + 1,
              column: pos.column
            };
            editor.setPosition(nPos);
          }
        }
      });

      editor.addAction({
        id: "myLeftArrow",
        label: "myLeftArrow",
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyJ],
        run: () => {
          const pos = editor.getPosition();
          if (pos?.column) {
            const nPos: monaco.IPosition = {
              lineNumber: pos.lineNumber,
              column: pos.column - 1
            };
            editor.setPosition(nPos);
          }
        }
      });

      editor.addAction({
        id: "mytLineStart",
        label: "mytLineStart",
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyH],
        run: () => {
          const pos = editor.getPosition();
          if (pos?.column) {
            const nPos: monaco.IPosition = {
              lineNumber: pos.lineNumber,
              column: 0
            };
            editor.setPosition(nPos);
          }
        }
      });

      editor.addAction({
        id: "myRightArrow",
        label: "myRightArrow",
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyL],
        run: () => {
          const pos = editor.getPosition();
          if (pos?.column) {
            const nPos: monaco.IPosition = {
              lineNumber: pos.lineNumber,
              column: pos.column + 1
            };
            editor.setPosition(nPos);
          }
        }
      });

      editor.addAction({
        id: "myLineEnd",
        label: "myLineEnd",
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.Semicolon],
        run: () => {
          const pos = editor.getPosition();
          if (pos?.column) {
            const nPos: monaco.IPosition = {
              lineNumber: pos.lineNumber,
              column: 99999
            };
            editor.setPosition(nPos);
          }
        }
      });

      // 添加自定义命令(会覆盖默认的命令)
      // editor.addCommand(
      // 	monaco.KeyCode.DownArrow,
      // 	() => {
      // 		console.log("下");
      // 		const pos = editor.getPosition();
      // 		if (pos?.lineNumber) {
      // 			const nPos: monaco.IPosition = {
      // 				lineNumber: pos.lineNumber + 1,
      // 				column: pos.column
      // 			}
      // 			editor.setPosition(nPos);
      // 		}
      // 	},
      // 	"!textInputFocus" // when 子句
      // );

      // 给父组件实时返回最新文本(v-model)
      editor.onDidChangeModelContent(() => {
        const value = editor.getValue();
        emit("update:modelValue", value);
        emit("change", value);
      });

      emit("editor-mounted", editor);
    };

    onMounted(() => {
      init();
    });

    // 更新编辑器的文本
    watch(
      () => props.modelValue,
      newValue => {
        if (editor) {
          const value = editor.getValue();
          if (newValue !== value) {
            editor.setValue(newValue);
          }
        }
      }
    );

    // 更新编辑器配置
    watch(
      () => props.options,
      newValue => {
        editor.updateOptions(newValue);
      },
      { deep: true }
    );

    // 更新编辑器的语言
    watch(
      () => props.language,
      newValue => {
        monaco.editor.setModelLanguage(editor.getModel()!, newValue);
      }
    );

    // 更新编辑器的主题
    watch(
      () => props.theme,
      newValue => {
        editor.updateOptions({
          theme: newValue
        });
      }
    );

    // 卸载
    onBeforeUnmount(() => {
      editor.dispose();
      window.removeEventListener("resize", handleWindowResize);
    });

    expose({ monaco });

    return { codeEditBox };
  }
});
</script>

<style lang="scss" scoped>
// .codeEditBox {
// 	width: v-bind(width);
// 	height: v-bind(height);
// }
</style>
